"""
Flickr photo search for Deskbar
Copyright (C) 2007 Fabio Corneti

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

A full copy of the GPL can be found at this URL:
http://www.fsf.org/licensing/licenses/gpl.txt

Initial ideas and stucture for this plugin provided by desklicious, included in the standard Deskbar plugins.
"""

import os, cgi, os.path, deskbar, deskbar.Match, deskbar.Handler, deskbar.Utils
import gnomevfs, gtk, gconf

from gettext import gettext as _
import xml.dom.minidom, urllib

VERSION='0.1.1'
FLICKR_REQUEST_TEMPLATE = 'http://api.flickr.com/services/feeds/photos_public.gne?tags=%s&format=rss_200'
GCONF_MAX_RESULTS = deskbar.GCONF_DIR + '/flickr/maxresults'
QUERY_DELAY = 1
THUMBNAIL_WIDTH = 75
MAX_RESULTS_RANGE_MAX = 64;

_debug=True
if _debug:
    import traceback

def _check_requirements():
	return (deskbar.Handler.HANDLER_IS_CONFIGURABLE, _("You can set the maximum number of results to return."), _on_config_account)
		
HANDLERS = {
    "FlickrHandler" : {
        "name": _("Flickr photo search"),
        "description": _("Search photos on Flickr."),
        "requirements" : _check_requirements,        
        "version": VERSION,
    }
}

class ThumbnailsCache():
    
    def __init__(self):
        self._cache = {}
        
    def put(self, url, pixbuf):
        self._cache[url] = pixbuf
        
    def get(self, url):
        return self._cache.get(url, None)
        
    def has_key(self, key):
        return key in self._cache.keys()
        
    def purge(self):
        self._cache = {}
        
thumbnailsCache = ThumbnailsCache()


def _on_config_account(dialog):
    dialog = gtk.Dialog(_("Flickr photo search preferences"), dialog,
                gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
    
    table = gtk.Table(rows=2, columns=2)
    
    table.attach(gtk.Label(_("Enter the maximum number of search results")), 0, 2, 0, 1)

    maxResultsAdjustment = gtk.Adjustment(value=0, lower=0, upper=MAX_RESULTS_RANGE_MAX, step_incr=1, page_incr=10, page_size=0)
    maxResultsSpinButton = gtk.SpinButton(adjustment=maxResultsAdjustment)
    maxResults = deskbar.GCONF_CLIENT.get_int(GCONF_MAX_RESULTS)
    
    maxResultsSpinButton.set_value(maxResults)
    
    table.attach(gtk.Label(_("Max results: ")), 0, 1, 1, 2)
    table.attach(maxResultsSpinButton, 1, 2, 1, 2)
    
    table.show_all()
    dialog.vbox.add(table)
    
    response = dialog.run()
    dialog.destroy()
    
    try:
        maxResults = int(maxResultsSpinButton.get_value())
    except:
        maxResults = 0
    
    if response == gtk.RESPONSE_ACCEPT:
        deskbar.GCONF_CLIENT.set_int(GCONF_MAX_RESULTS, maxResults)


class FlickrMatch(deskbar.Match.Match):    
    
    def __init__(self, handler, url=None, tags=None, author=None, thumbnail=None, **args):
        deskbar.Match.Match.__init__ (self, handler, **args)
        self.url = url
        self.tags = tags
        self.author = author
        self.thumbnail = thumbnail
        
    def get_verb(self):
        return "<b>%(name)s</b>\n<span size='small'><i>%(author)s</i></span>\n<span size='small' foreground='grey'>%(tags)s</span>"
    
    def get_name(self, text=None):
        return {
            "name": cgi.escape(self.name),
            "thumbnail" : self.thumbnail,
            "author" : self.author,
            "tags": cgi.escape(' '.join(self.tags)),
        }
        
    def action(self, text=None):
        deskbar.Utils.url_show(self.url)

    def get_category(self):
        return "web"

    def get_hash(self, text=None):
        return self.url

    def get_icon(self):
        if thumbnailsCache.has_key(self.thumbnail):
            return thumbnailsCache.get(self.thumbnail)
        else:
            thumb = urllib.urlopen(self.thumbnail, proxies=deskbar.Utils.get_proxy())
            data = thumb.read()
            pixbufLoader = gtk.gdk.PixbufLoader()
            pixbufLoader.write(data)
            pixbuf = pixbufLoader.get_pixbuf()
            pixbufLoader.close()
            
            if pixbuf.get_width() > 1:
                w = h = THUMBNAIL_WIDTH
                #TODO: implement scaling
                thumbnailsCache.put(self.thumbnail, pixbuf);
                return pixbuf
            else:
                return deskbar.Match.Match.get_icon(self)
        
class FlickrHandler(deskbar.Handler.AsyncHandler):

    def __init__(self):
        deskbar.Handler.AsyncHandler.__init__ (self, "yahoo.png")
        self._flickrClient = FlickrClient(self)

    def query(self, tag):
        thumbnailsCache.purge()
        self.check_query_changed (timeout=QUERY_DELAY)
        self.check_query_changed ()
        images = self._flickrClient.getPhotosByTag(tag)
        self.check_query_changed (timeout=QUERY_DELAY)
        return images


class FlickrClient:

    def __init__(self, handler):
        self.handler = handler
        
    def getPhotosByTag(self, tag):
        maxResults = deskbar.GCONF_CLIENT.get_int(GCONF_MAX_RESULTS)
        
        photos=[]    
        url = "http://api.flickr.com/services/feeds/photos_public.gne?tags=%s&format=rss_200" % urllib.quote_plus(tag)
        
        stream = urllib.urlopen(url, proxies=deskbar.Utils.get_proxy())
        dom = xml.dom.minidom.parse(stream)
        stream.close()
        
        resultsCount = 0
        for item in dom.getElementsByTagName("item"):
            
            if maxResults > 0 and resultsCount == maxResults:
                break
            
            photos.append(
                FlickrMatch(self.handler, 
                    name=item.getElementsByTagName("title")[0].firstChild.nodeValue,
                    url=item.getElementsByTagName("link")[0].firstChild.nodeValue,
                    tags=item.getElementsByTagName("media:category")[0].firstChild.nodeValue.split(" "),
                    author=item.getElementsByTagName("author")[0].firstChild.nodeValue,
                    thumbnail=item.getElementsByTagName("media:thumbnail")[0].attributes["url"].nodeValue))
            
            resultsCount = resultsCount + 1
                            
        return photos


    
